package tmhprediction.optimization;

import tmhprediction.classification.TMHClassifier;
import tmhprediction.eval.TMHHelixEvaluator;
import tmhprediction.eval.TMHResidueEvaluator;
import tmhprediction.main.TMHResultMap;

public class GridSearchSequential
{
	/**
	 * TODO TODO TODO (wg. alice!)
	 * Values are used as 2^
	 * @param cMin
	 * @param cMax
	 * @param gMin
	 * @param gMax
	 * @param cStep
	 * @param gStep
	 * @param instTrain
	 * @param instTest	Actually crosstrain
	 * @return
	 * @throws Exception 
	 */
	public static double[] performGridSearch(double cMin, double cMax, double gMin, double gMax, double cStep, double gStep,
			String pathTrain, String pathTest, boolean isSVM1, int cacheSize)
	{		
		double bestScore = 0.0;
		int bestCutoff = 0;	//only if SVM1
		double bestC = Double.MIN_VALUE;
		double bestG = Double.MAX_VALUE;
		
		for(double i = cMin; i <= cMax; i = i + cStep)
		{
			for (double j = gMin; j <= gMax; j = j + gStep)
			{
				System.out.println("Now testing (c and g): " + i + " " + j);
				double finC = Math.pow(2.0, i);
				double finG = Math.pow(2.0, j);
				
				TMHResultMap resM = null;
				try
				{
					TMHClassifier classifier = new TMHClassifier(pathTrain, pathTest, finG,finC, cacheSize);
					resM = classifier.createResultMap();
				}
				catch(Exception e)
				{
					System.out.println("Error while training/testing of classifier");
					e.printStackTrace();
					System.exit(1);
				}
				
				if(isSVM1)
				{
					TMHResultMap tempMap = TMHResidueEvaluator.evaluateProteins(resM);
					double[] temp =  findBestCutoff(tempMap);
					if(temp[0] > bestScore)
					{
						//new MCC is better than old
						bestScore = temp[0];
						bestCutoff = (int) temp[1];
						bestC = i;
						bestG = j;
					}
				}
				else
				{
					//second SVM
					double qokTemp  = 0.0;
//					temp1 = TMHResidueEvaluator.calcPerResidueScoresSilent(resM);
					qokTemp = TMHHelixEvaluator.berechneFormelnSilent(TMHHelixEvaluator.finalHelixEvaluation(resM))[0];
					if(qokTemp > bestScore)
					{
						bestScore = qokTemp;
						bestC = i;
						bestG = j;
					}
					
				}
			}
		}
		return new double[]{bestC, bestG, bestCutoff};
		
	}
	
	private static double[] findBestCutoff(TMHResultMap map)
	{
		int bestCutoff = -1;
		double bestMcc = Double.MIN_VALUE;
		
		for(int i = 0; i < 10; i++)
		{
			int tp = 0, fp =0 , tn = 0, fn = 0;
			for(String prot : map.keySet())
			{
				if(map.get(prot)[TMHResultMap.CONFIDENCE] >= i)
				{
					if(map.get(prot)[TMHResultMap.OBSERVED] > 0)
					{
						tp++;
					}
					else
					{
						fp++;
					}
				}
				else
				{
					if(map.get(prot)[TMHResultMap.OBSERVED] > 0)
					{
						fn++;
					}
					else
					{
						tn++;
					}
				}
			}
			double tempMcc = ((tp * tn) - (fp * fn))
		    		/ Math.sqrt(((tp + fp) * (tp + fn) * (tn + fp) * (tn + fn)));
			if(tempMcc > bestMcc)
			{
				bestMcc = tempMcc;
				bestCutoff = i;
			}
		}
		
		
		return new double[]{bestMcc, bestCutoff};
	}
	
}
